
#include "Framework.h"
#include <mqueue.h>
#include <errno.h>
#include <string>

using namespace std;

/* constructor */
TFW_EventQueue::TFW_EventQueue(string name, TFW_EventDispatcher* eventDispatcher, int max_msg_num, int max_size_mqueue)
	:m_mqId(name),
	m_msg_max_num(max_msg_num),
	m_msg_max_size(max_size_mqueue),
	m_dispatcher(eventDispatcher)
{
	eventDispatcher->registEventQueue(this);
}

TFW_EventQueue::~TFW_EventQueue()
{
	/* remove event queue from event dispatcher */
	if(NULL != m_dispatcher)
	{
		m_dispatcher->removeEventQueue(this);
	}
	
	/* delete mqueue from system */
	mqd_t rtn = mq_unlink(m_mqId.c_str());
	if(rtn == 0)
	{
		/* success */
	}
}

/* initialize */
void TFW_EventQueue::initialize()
{
	/* ///////initialize status/////// */
}

/* start */
void TFW_EventQueue::start()
{
	struct mq_attr attr;
	attr.mq_maxmsg = m_msg_max_num;
	attr.mq_msgsize = m_msg_max_size;
	
	/* open mqueue */
	m_mFd = mq_open(("/" + m_mqId).c_str(), O_RDWR | O_CREAT | O_EXCL | O_NONBLOCK, 0666, &attr);
	if(m_mFd == (mqd_t)-1)
	{
		/* log write */
		cout<<"mq_open() failure : "<<errno<<endl;
		return ;
	}
}

/* post event to this queue */
void TFW_EventQueue::postEvent(TFW_Event* event)
{
	/* serialize */
	TFW_Stream buf;
	event->serialize(buf);
	
	/* post event to this mqueue */
	mqd_t rtn = mq_send(m_mFd, buf.getbuf(), buf.getlen(), 8);
	if(rtn == (mqd_t)-1)
	{
		/* log write */
		cout<<"mq_send failure : "<<errno<<endl;
	}
}

/* peel event from mqueue */
TFW_Event*  TFW_EventQueue::peekEvent()
{
	/* initialize buffer */
	char* buf = (char*)malloc(1024);
	memset(buf, 0x00, sizeof(buf));
	
	unsigned int prio;
	mqd_t mqd;
	struct mq_attr attr;
	mqd_t rtnGetattr = mq_getattr(m_mFd, &attr);
	if(rtnGetattr < 0)
	{
		cout<<"mq_getattr failure :"<<errno<<endl;
		return NULL;
	}
	/* peek event from mqueue */
	mqd_t rtn = mq_receive(m_mFd, buf, attr.mq_msgsize, &prio);
	if(rtn == (mqd_t)-1)
	{
		cout<<"mq_receive failure : "<<errno<<endl;
		return NULL;
	}
	
	/* get id (****no endian check***) */
	int evtID = *(int*)buf;
	
	return creatEvent(evtID);
}

/* crate event by event id */
TFW_Event* TFW_EventQueue::creatEvent(int id)
{
	switch(id)
	{
		case evStartAllProcess::ID : return new evStartAllProcess; break;
		case evKillAllProcess::ID : return new evKillAllProcess; break;
		default : return NULL; break;
	}
}
